package com.mt.api.core.config.aop;

import cn.hutool.core.exceptions.ExceptionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.slf4j.Logger;
import org.springframework.http.HttpMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 日志拦截
 *
 * @author: plover
 * @date: 2021/1/1 9:19 上午
 */
public abstract class AbstractAopLog {

    private static final String METHOD_ERROR_PREFIX = "mtd.err.";
    private static final String METHOD_FORM = "form";
    private String MATCH_PATTERN = "";
    private static final String MATCH_PATTERN_TEMPLATE = "(:\\s*\"[^,\":]{%s,}?\")";

    /**
     * 环绕入口
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "allMethods()")
    protected Object around(final ProceedingJoinPoint joinPoint) throws Throwable {
        Map methodMap = new HashMap();
        //获取请求类名、方法名
        String serviceName = joinPoint.getSignature().getDeclaringType().getSimpleName();
        String methodNameSource = joinPoint.getSignature().getName();
        String methodName = serviceName + "." + methodNameSource;
        //获取返回值
        Object proceed = null;
        Throwable errStack = null;
        long startTime = System.currentTimeMillis();
        String currentTime = getCurrentTime();
        try {
            proceed = joinPoint.proceed();
        } catch (Throwable throwable) {
            errStack = throwable;
            throw throwable;
        } finally {
            long costTime = System.currentTimeMillis() - startTime;
            if (getLogOpen() && getLogger().isInfoEnabled()) {
                HttpServletRequest request = null;
                //获取客户端Ip
                String requestIp = "";
                //获取请求url
                String requestUrl = "";
                // 获取请求头
                Map headerMap = new HashMap();
                //获取请求类型
                String requestMethod = "";
                //获取请求参数
                StringBuffer requestParams = new StringBuffer();
                if (null != RequestContextHolder.getRequestAttributes()) {
                    request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
                }
                if (null != request) {
                    //获取客户端Ip
                    requestIp = getRemoteHost(request);
                    //获取请求url
                    requestUrl = request.getRequestURL().toString();
                    Enumeration<String> enumeration = request.getHeaderNames();
                    while (enumeration.hasMoreElements()) {
                        String name = enumeration.nextElement();
                        String value = request.getHeader(name);
                        headerMap.put(name, value);
                    }
                    //获取请求类型
                    requestMethod = request.getMethod();
                    // get请求
                    if (HttpMethod.GET.toString().equals(requestMethod)) {
                        String queryString = request.getQueryString();
                        if (StringUtils.isNotBlank(queryString)) {
                            requestParams.append(queryString);
                        }
                    } else {//其他请求
                        String contentType = request.getContentType();
                        if (contentType != null && contentType.contains(METHOD_FORM)) {
                            Map formDataMap = new HashMap();
                            Enumeration<String> formDataEnum = request.getParameterNames();
                            while (formDataEnum.hasMoreElements()) {
                                String name = formDataEnum.nextElement();
                                String value = request.getParameter(name);
                                formDataMap.put(name, value);
                            }
                            requestParams.append(JSON.toJSONString(formDataMap));
                        } else {
                            // StringWriter writer = new StringWriter();
                            // IOUtils.copy(request.getInputStream(), writer, StandardCharsets.UTF_8.name());
                            // String result = writer.toString();
                            // // 如果请求的字段长度超长，则对长度大于3000的字段进行屏蔽
                            // if (request.getContentLengthLong() > getContentLengthLimit()) {
                            //     result = result.replaceAll(getMatchPattern(), ":\"*\"");
                            // }
                            // requestParams.append(result);
                            requestParams.append(assemblyLog(joinPoint.getArgs()));
                        }
                    }
                }
                //获取服务端Ip
                String serverIp = getLinuxLocalIp();
                methodMap.put("time", currentTime);
                methodMap.put("requestIp", requestIp);
                methodMap.put("serverIp", serverIp);
                methodMap.put("requestUrl", requestUrl);
                methodMap.put("requestHeaders", JSON.toJSONString(headerMap));
                methodMap.put("requestMethod", requestMethod);
                methodMap.put("methodName", methodName);
                methodMap.put("requestParams", String.valueOf(requestParams));
                if (Objects.nonNull(proceed)) {
                    methodMap.put("response", JSON.toJSONString(proceed));
                }
                methodMap.put("costTime", costTime);
                String errStackStr = Objects.isNull(errStack) ? StringUtils.EMPTY : ExceptionUtil.getMessage(errStack);
                methodMap.put("errStack", errStackStr);
                methodMap.put("errCode", StringUtils.isNotBlank(errStackStr) ? 1 : 0);
                getLogger().info(JSON.toJSONString(methodMap));
            }
        }
        return proceed;
    }

    public static String getCurrentTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        String dt = sdf.format(new Date());
        return dt;
    }

    protected abstract Logger getLogger();

    public abstract void allMethods();

    protected abstract boolean getLogOpen();

    protected long getContentLengthLimit() {
        return 5000;
    }

    private String getMatchPattern() {
        return String.format(MATCH_PATTERN_TEMPLATE, getKeyMaxLimit());
    }

    protected long getKeyMaxLimit() {
        return 3000;
    }

    public static String assemblyLog(Object[] params) {
        StringBuilder sb = new StringBuilder();
        try {
            for (Object object : params) {
                if (object == null) {
                    sb.append("null");
                    continue;
                }
                if (object instanceof ServletRequest) {
                    sb.append("request");
                } else if (object instanceof ServletResponse) {
                    sb.append("response");
                } else if (object instanceof MultipartFile) {
                    sb.append("MultipartFile");
                } else {
                    sb.append(JSONObject.toJSON(object));
                }
            }
        } catch (Exception e) {
            System.out.println("");
        }

        return sb.toString();
    }

    /**
     * 获取目标主机的ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }

    /**
     * 获取Linux下的IP地址
     */
    private static String getLinuxLocalIp() throws SocketException {
        String ip = "";
        try {
            for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
                NetworkInterface intf = en.nextElement();
                String name = intf.getName();
                if (!name.contains("docker") && !name.contains("lo")) {
                    for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                        InetAddress inetAddress = enumIpAddr.nextElement();
                        if (!inetAddress.isLoopbackAddress()) {
                            String ipaddress = inetAddress.getHostAddress().toString();
                            if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") && !ipaddress.contains("fe80")) {
                                ip = ipaddress;
                            }
                        }
                    }
                }
            }
        } catch (SocketException ex) {
            ip = "127.0.0.1";
            ex.printStackTrace();
        }
        return ip;
    }
}
